// Copyright 2012 Dave Ruest.  All rights reserved.

/**
 * @fileoverview The background animates the lowest ui layer, moving
 * columns of tiled artwork across the screen. A single "mission" will consist of a start
 * at the hive, three sections with different art and an end back at the hive. This is
 * implemented with the background keeping an array of tile objects, created at need
 * by an array of "stages" (really tile generators but a player might call it a stage for 
 * lack of a better word).
 * 
 * This file contains the background "facade" as well as the stage, column and tile
 * objects required to implement an animated background.
 * 
 * @author Dave Ruest dave.ruest@gmail.com
 */

/**
 * Background constructor. Store stages (tile column generators) and used them
 * to create tile columns as required.
 * 
 * @param {Game} game the "singleton" game instance
 * @param {Number} tileSize the height and width of a single tile of background art
 * @param {Array} stages an array of column tile generators
 */
function Background(game, tileSize, stages) {
	this.game = game;
	this.tileSize = tileSize;
	this.stages = stages;
	
	// background only instantiates the tiles it needs to cover the screen
	// more are generated only when needed
	this.nColumns = Math.ceil(game.width / this.tileSize);
	this.nRows = Math.ceil(game.height / this.tileSize);
	
	this.columns = new Array();
	for (var i = 0; i <= this.nColumns; i++) {
		this.push(i * this.tileSize);
	}
};

/**
 * Draws the background layer.  Called from the game event loop but this
 * may evolve into something more formal.
 */
Background.prototype.draw = function() {
	for (var c = 0; c < this.columns.length; c++) {
		this.columns[c].draw();
	}
};

Background.prototype.getCollision = function(x, y) {
	var column, tile, station, sx, sy;
	// iterate the first three columns (bee cannot move forward)
	for (var c = 0; c < 3; c++) {
		column = this.columns[c];
		// iterate each tile in the column
		for (var r = 0; r < column.tiles.length; r++) {
			tile = column.tiles[r];
			station = tile.station;
			if (station) {
				sx = column.x + station.x;
				if (Math.abs(sx - x) < this.tileSize / 2) {
					sy = tile.y + station.y;
					if (Math.abs(sy - y) < this.tileSize / 4) {
						return station;
					}
				}
			}
		}
	}
	return null;
};

/**
 * Updates the background layer. 
 */
Background.prototype.onInterval = function() {
	var column;
	for (var c = 0; c < this.columns.length; c++) {
		column = this.columns[c];
		column.x += this.game.dx;
		
		if (column.x < 1 - this.tileSize) {
			column = this.columns.shift();
			var last = this.columns[this.columns.length - 1];
			this.push(last.x + this.tileSize);
			this.columns[0].x -= 2;
		}
	}
};

/**
 * Generate and add a new column to the background. Used both when 
 * initially creating the background and to replace columns scrolled off screen.
 * Note that this may also "scroll off" a stage, and that when there are no more
 * stages to "scroll on" the mission is over.
 * 
 * @param {Number} x the x coordinate of the column to be generated 
 * @private intended solely for the use of a the background
 */
Background.prototype.push = function(x) {
	// TODO don't just pause
	// show a summary of honey collected etc.
	// and show a button allowing a restart
	if (this.stages[0].isDone()) {
		this.stages.shift();
		if (this.stages.length == 0) {
			this.game.start = new End(game);
		}
	}
	
	this.columns.push(new Column(this.stages[0], this.nRows, x, this.tileSize));
	this.stages[0].columnIndex++;
};

/**
 * Stage constructor. Really more of a tile column generator.
 * @param {Game} game the singleton game instance
 * @param {ImageGrid} images a grid of tile-able images 
 * @param {Number} maxColumns the maximum number of tile columns the stage should generate
 */
function Stage(game, images, maxColumns) {
	this.images = images;
	this.maxColumns = maxColumns;
	this.columnIndex = 0;
};

/**
 * @returns {Boolean} true if the stage has not already generated its alloted number
 * of tile columns
 */
Stage.prototype.isDone = function() {
	return this.columnIndex >= this.maxColumns;
};

/**
 * 
 * @param {Number} r
 * @param {Number} c
 * @returns {Station}
 */
Stage.prototype.getStation = function(r, c) {
	if (this.stations) {
		var station;
		for (var i = 0; i < this.stations.length; i++) {
			station = this.stations[i];
			if (r == station.r && c == station.c) {
				return station;
			}
		}
	}
	return null;
};

/**
 * Column constructor.
 * @param stage
 * @param x
 * @returns {Column}
 */
function Column(stage, rows, x, tileSize) {
	this.images = stage.images;
	this.x = x;
	this.tiles = new Array();
	for (var i = 0; i < rows; i++) {
		this.tiles.push(new Tile(stage, i * tileSize));
	}
};

Column.prototype.draw = function() {
	var tile;
	for (var r = 0; r < this.tiles.length; r++) {
		tile = this.tiles[r];
		this.images.draw(this.x, tile.y, tile.r, tile.c);
	}
};

/**
 * Tile constructor.
 * @param {Stage} stage
 * @param {Number} y
 * @returns {Tile}
 */
function Tile(stage, y) {
	this.y = y;
	this.r = this.random(stage.images.rows);
	
	if (stage.columnIndex == 0) {
		// assumes some structure in the tiled art
		// first column is left edge, suitable to tile *after* another stage
		this.c = 0;
	} else if (stage.columnIndex < stage.maxColumns - 1) {
		// middle columns
		this.c = Math.floor(Math.random() * (stage.images.columns - 2)) + 1;
	} else {
		// last column is right edge, suitable to tile *before* another stage
		this.c = stage.images.columns - 1;
	}
	
	this.station = stage.getStation(this.r, this.c);
};

Tile.prototype.random = function(ceiling) {
	// TODO modify this distribution...
	// flowers should be ~10%, hazards ~20%?
	// interesting note, could add rows until this distribution is achieved...
	// larger image but more varied background
	for (var i = 0; i < ceiling; i++) {
		if (Math.floor(Math.random() * 2)) {
			return i;
		}
	}
	return 0;
};

/**
 * Station constructor. Represents a stationary object in a background.
 * May be a bonus (flower) or a hazard (pesticide).
 * @param {String} id an identifier for the stationary object i.e. "flower"
 */
function Station(id, r, c, x, y) {
	this.id = id;
	
	// used during tile construction
	this.r = r;
	this.c = c;
	
	// used during collision detection
	this.x = x;
	this.y = y;
};
